﻿using System.Threading;

namespace eLoop;

class SingleUnsyncQueueScheduler : ASingleScheduler
#if NETCOREAPP
    , IThreadPoolWorkItem
#endif
{
    private static int index = 0;

    public SingleUnsyncQueueScheduler()
    {
        Interlocked.Increment(ref index);

        this.Id = $"queue:{index}";
        this.Name = $"thread_pool_{index}";
        
#if NETSTANDARD2_0 || NETSTANDARD2_1
        this.execute_callBack = this.Execute;
#endif
        base.InitializationSyncContext();
    }
    
    private int _doingWork;
    
#if NETSTANDARD2_0 || NETSTANDARD2_1
    private readonly WaitCallback execute_callBack;
#endif

    protected override void ExecuteLoop()
    {
        if (Interlocked.CompareExchange(ref _doingWork, 1, 0) == 0)
        {
#if NETSTANDARD2_0 || NETSTANDARD2_1
            System.Threading.ThreadPool.UnsafeQueueUserWorkItem(this.execute_callBack, null);
#elif NETCOREAPP
            System.Threading.ThreadPool.UnsafeQueueUserWorkItem(this, preferLocal: false);
#endif
        }
    }

#if NETSTANDARD2_0 || NETSTANDARD2_1
    private void Execute(object state)
#elif NETCOREAPP
    void IThreadPoolWorkItem.Execute()
#endif
    {
        this.StartExecute();
    }

    protected virtual void StartExecute()
    {
        while (true)
        {
            base.DeliverWorks();

            _doingWork = 0;

            Thread.MemoryBarrier();

            if (base.IsEmpty())
            {
                break;
            }

            if (Interlocked.Exchange(ref _doingWork, 1) == 1)
            {
                break;
            }
        }
    }

    public override void Dispose()
    {
        if (this.IsDisposed)
        {
            return;
        }

        this.Reset();
    }

    protected void Reset()
    {
        base.Dispose();
    }
}
